﻿using System;
using System.Collections.Generic;

using TrainSimulator.Interfaces;
using TrainSimulator.Model.Track;
using TrainSimulator.Model.Train;
using TrainSimulator.Model.Driver;
using TrainSimulator.Model.Engine;


namespace TrainSimulator
{
    public class Simulator
    {
        #region Singleton

        private static volatile Simulator _instance = null;
        private static readonly object TOKEN = new object();
        public static Simulator Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (TOKEN)
                    {
                        if (_instance == null)
                            _instance = new Simulator();
                    }
                }
                return _instance;
            }
        }

        #endregion

        private const double _trackLength = 100;
        private const double _angle = 45;
        private const int _amountOfTracks = 8;
        private Dispatcher _dispatcher;

        public List<ITrain> Trains { get; set; }
        public List<ITrack> Tracks { get; set; }
        public ITrack StartTrack { get; set; }

        private Simulator()
        {
            this.Tracks = new List<ITrack>();
            this.Trains = new List<ITrain>();

            // Test Data
            this.StartTrack = GenerateTracks(true);
            this.Trains = GenerateTrains();

            _dispatcher = new Dispatcher(Trains.ToArray());
        }

        private ITrack GenerateTracks(bool connected)
        {
            ITrack start = new SimpleTrack(0, _trackLength, 0, _angle);

            StartTrack = start;
            Tracks.Add(start);
            ITrack prev = start;
            ITrack next = null;
            for (int i = 1; i < _amountOfTracks; i++)
            {
                next = new SimpleTrack(i, _trackLength, prev.Angle, _angle);
                Tracks.Add(next);

                prev.NextTrack = next;
                next.Previous = prev;
                if (i == _amountOfTracks - 1 && connected) // If connected tracks
                {
                    next.NextTrack = start;
                    start.Previous = next;
                }
                prev = next;
                //if (prev == start)
                //    start.PreviousTrack = next;
            }

            return start;
        }
        private List<ITrain> GenerateTrains()
        {
            List<ITrain> trains = new List<ITrain>();
            //trains.Add(GenerateTrainSet(0, "Train A", 4, 80, StartTrack.NextTrack.NextTrack, false));
            trains.Add(GenerateTrain(1, "Train B", 4, 60, StartTrack, false));
            return trains;
        }
        private ITrain GenerateTrain(int id, string desc, int numOfWagons, float speed, ITrack startTrack, bool reverse)
        {
            ITrain train = new Train(id, desc, startTrack, reverse);
            for (int i = 0; i < numOfWagons; i++)
            {
                train.AddWagon(new Wagon(i, "wagon " + i, 100, 40));
            }
            train.LocoDriver = new LocoDriver(train);
            train.Engine = new TrainEngine(train);
            train.RequestedSpeed = speed;
            return train;
        }

        #region Public Methods

        public void Start()
        {
            _dispatcher.Create();
            foreach (var train in Trains)
                train.LocoDriver.Start();
        }

        public void Stop()
        {
            foreach (var train in Trains)
                train.LocoDriver.Stop();
        }

        #endregion
    }
}
